using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Globalization;

namespace Camalon.ColorPicker
{
	/// <summary>
	/// Summary description for ColorListView.
	/// </summary>
    [ToolboxItem(false)]
	public class ColorListView : System.Windows.Forms.ListView
	{

		
		private System.Windows.Forms.ImageList largeImageList;
		private System.Windows.Forms.ImageList smallImageList;
		private System.Windows.Forms.ColumnHeader columnName;
		private System.Windows.Forms.ColumnHeader columnOpacity;
		private System.Windows.Forms.ColumnHeader columnHex;
		private System.Windows.Forms.ColumnHeader columnR;
		private System.Windows.Forms.ColumnHeader columnG;
		private System.Windows.Forms.ColumnHeader columnB;
		private System.Windows.Forms.ColumnHeader columnH;
		private System.Windows.Forms.ColumnHeader columnS;
		private System.Windows.Forms.ColumnHeader columnBr;
		private System.Windows.Forms.ColumnHeader columnC;
		private System.Windows.Forms.ColumnHeader columnM;
		private System.Windows.Forms.ColumnHeader columnY;
		private System.Windows.Forms.ColumnHeader columnK;
		private System.ComponentModel.IContainer components;

		public ColorListView()
		{

			// This call is required by the Windows.Forms Form Designer.
			InitializeComponent();

			// TODO: Add any initialization after the InitComponent call
			this.DataSource = new ColorDataSet();
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if( components != null )
					components.Dispose();
			}
			base.Dispose( disposing );
		}

		#region Component Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			this.largeImageList = new System.Windows.Forms.ImageList(this.components);
			this.smallImageList = new System.Windows.Forms.ImageList(this.components);
			this.columnName = new System.Windows.Forms.ColumnHeader();
			this.columnR = new System.Windows.Forms.ColumnHeader();
			this.columnG = new System.Windows.Forms.ColumnHeader();
			this.columnB = new System.Windows.Forms.ColumnHeader();
			this.columnOpacity = new System.Windows.Forms.ColumnHeader();
			this.columnHex = new System.Windows.Forms.ColumnHeader();
			this.columnH = new System.Windows.Forms.ColumnHeader();
			this.columnS = new System.Windows.Forms.ColumnHeader();
			this.columnBr = new System.Windows.Forms.ColumnHeader();
			this.columnC = new System.Windows.Forms.ColumnHeader();
			this.columnM = new System.Windows.Forms.ColumnHeader();
			this.columnY = new System.Windows.Forms.ColumnHeader();
			this.columnK = new System.Windows.Forms.ColumnHeader();
			// 
			// largeImageList
			// 
			this.largeImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit;
			this.largeImageList.ImageSize = new System.Drawing.Size(32, 32);
			this.largeImageList.TransparentColor = System.Drawing.Color.Transparent;
			// 
			// smallImageList
			// 
			this.smallImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit;
			this.smallImageList.ImageSize = new System.Drawing.Size(24, 18);
			this.smallImageList.TransparentColor = System.Drawing.Color.Transparent;
			// 
			// columnName
			// 
			this.columnName.Text = "Name";
			this.columnName.Width = 100;
			// 
			// columnR
			// 
			this.columnR.Text = "R";
			this.columnR.Width = 30;
			// 
			// columnG
			// 
			this.columnG.Text = "G";
			this.columnG.Width = 30;
			// 
			// columnB
			// 
			this.columnB.Text = "B";
			this.columnB.Width = 30;
			// 
			// columnOpacity
			// 
			this.columnOpacity.Text = "A";
			this.columnOpacity.Width = 30;
			// 
			// columnHex
			// 
			this.columnHex.Text = "Hex";
			this.columnHex.Width = 70;
			// 
			// columnH
			// 
			this.columnH.Text = "H";
			this.columnH.Width = 30;
			// 
			// columnS
			// 
			this.columnS.Text = "S";
			this.columnS.Width = 30;
			// 
			// columnBr
			// 
			this.columnBr.Text = "B";
			this.columnBr.Width = 30;
			// 
			// columnC
			// 
			this.columnC.Text = "C";
			this.columnC.Width = 30;
			// 
			// columnM
			// 
			this.columnM.Text = "M";
			this.columnM.Width = 30;
			// 
			// columnY
			// 
			this.columnY.Text = "Y";
			this.columnY.Width = 30;
			// 
			// columnK
			// 
			this.columnK.Text = "K";
			this.columnK.Width = 30;
			// 
			// ColorListView
			// 
			this.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
																			  this.columnName,
																			  this.columnR,
																			  this.columnG,
																			  this.columnB,
																			  this.columnOpacity,
																			  this.columnHex,
																			  this.columnH,
																			  this.columnS,
																			  this.columnBr,
																			  this.columnC,
																			  this.columnM,
																			  this.columnY,
																			  this.columnK});
			this.FullRowSelect = true;
			this.GridLines = true;
			this.HideSelection = false;
			this.LargeImageList = this.largeImageList;
			this.MultiSelect = false;
			this.SmallImageList = this.smallImageList;

		}
		#endregion


		#region Dataset

		private ColorDataSet _dataSource;

		[Browsable( false)]
		[DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden)]
		public ColorDataSet DataSource
		{
			get
			{ 
				return _dataSource;
			}
			set
			{
				if( _dataSource != null)
				{
					_dataSource.Color.ColorRowChanged-=new ColorPicker.ColorDataSet.ColorRowChangeEventHandler(ColorRowChanged);
					_dataSource.Color.ColorRowDeleted-=new ColorPicker.ColorDataSet.ColorRowChangeEventHandler(ColorRowDeleted);
				}
				_dataSource = null;

				_dataSource = value;

				InitializeDataSource();
				
				if( _dataSource != null)
				{
					_dataSource.Color.ColorRowChanged+=new ColorPicker.ColorDataSet.ColorRowChangeEventHandler(ColorRowChanged);
					_dataSource.Color.ColorRowDeleted+=new ColorPicker.ColorDataSet.ColorRowChangeEventHandler(ColorRowDeleted);
				}

			}
		}


		private bool _dataSetInitializing;
		private void InitializeDataSource()
		{
			
			if( _dataSource == null) return;
			_dataSetInitializing = true;
			BeginUpdate();
			try
			{

				this.Items.Clear();
				this.smallImageList.Images.Clear();
				this.largeImageList.Images.Clear();

				foreach( ColorDataSet.ColorRow c in _dataSource.Color.Rows)
				{
					if( c.RowState == DataRowState.Deleted || c.RowState == DataRowState.Detached) continue;
					AddColor( c );
				}
			}
			finally
			{
				EndUpdate();
				_dataSetInitializing = false;
				if( Items.Count > 0) Items[0].Selected = true;

			}

		}

		public void AddColor( string name, int opacity, int red, int green, int blue )
		{
			_dataSource.Color.AddColorRow( name, opacity, red, green, blue );//Doesnt fire change event
		}

		private void AddColor( ColorDataSet.ColorRow colorRow )
		{
			this.smallImageList.Images.Add( MakeImage( colorRow, true));
			this.largeImageList.Images.Add( MakeImage( colorRow, false));

			Color color  = Color.FromArgb(colorRow.Opacity,colorRow.Red, colorRow.Green, colorRow.Blue);
			HSB hsb = ColorConverter.ColorToHsb(color);
			CMYK cmyk = ColorConverter.RGBtoCMYK ( new RGB( colorRow.Red, colorRow.Green, colorRow.Blue));
			string[] s = new string[]{ 
										 colorRow.Name, 
										 colorRow.Red.ToString(null,null), 
										 colorRow.Green.ToString(null,null), 
										 colorRow.Blue.ToString(null,null), 
										 colorRow.Opacity.ToString(null,null), 
										 ColorConverter.ARGBToHexString( color ),
										 hsb.Hue.ToString(null,null),
										 hsb.Saturation.ToString(null,null),
										 hsb.Brightness.ToString(null,null),
										 cmyk.Cyan.ToString(null,null),	
										 cmyk.Magenda.ToString(null,null),	
										 cmyk.Yellow.ToString(null,null),	
										 cmyk.Key.ToString(null,null)
									};

			ListViewItem lvi			= new ListViewItem( s, Items.Count );
			lvi.ImageIndex				= this.smallImageList.Images.Count -1;
			lvi.Tag						= colorRow;
			lvi.UseItemStyleForSubItems = false;
				
				//RGBA
				lvi.SubItems[1].BackColor = 
				lvi.SubItems[2].BackColor = 
				lvi.SubItems[3].BackColor = 
				lvi.SubItems[4].BackColor = Color.LemonChiffon;
				//HEX
				lvi.SubItems[5].BackColor = Color.LavenderBlush;
				//HSB
				lvi.SubItems[6].BackColor = 
				lvi.SubItems[7].BackColor = 
				lvi.SubItems[8].BackColor = Color.LemonChiffon;
				//CMYK
				lvi.SubItems[9].BackColor = 
				lvi.SubItems[10].BackColor = 
				lvi.SubItems[11].BackColor = 
				lvi.SubItems[12].BackColor =Color.LavenderBlush; 
			
			Items.Add( lvi );


			if( _dataSetInitializing ) return;
			foreach( ListViewItem lvis in this.SelectedItems) lvis.Selected = false;
			lvi.Selected = true;
			lvi.EnsureVisible();
		}


		private void RemakeImages()
		{
			this.smallImageList.Images.Clear();
			this.LargeImageList.Images.Clear();


			for( int i= 0; i < Items.Count; i++)
			{
				this.smallImageList.Images.Add( MakeImage( (ColorDataSet.ColorRow)(Items[i].Tag), true));
				this.largeImageList.Images.Add( MakeImage( (ColorDataSet.ColorRow)(Items[i].Tag), false));
				Items[i].ImageIndex = i;
			}
		}

		private void Remove( ColorDataSet.ColorRow c )
		{
			//Color row state must be deleted state
			for( int i= 0; i < Items.Count; i++)
			{
				if( Items[i].Tag == c )
				{
					if( c.RowState == DataRowState.Deleted || c.RowState == DataRowState.Detached )
					{
						smallImageList.Images.RemoveAt(Items[i].ImageIndex );
						largeImageList.Images.RemoveAt( Items[i].ImageIndex );
						Items.RemoveAt( Items[i].Index );
						RemakeImages();
					}
					else
					{
						RemoveAt( i );
					}
					
					if( Items.Count > 0 )
					{
						if( i == Items.Count ) Items[ i-1].Selected = true;
						else Items[i].Selected = true;
					}


					break;
				}

			}
		}


		public void RemoveAt( int index )
		{
			RemoveAt(index, true );				
		}

		private void RemoveAt( int index , bool update)
		{
			RemoveAt( index, update, true);
		}

		private void RemoveAt( int index , bool update, bool select)
		{
			if( update ) BeginUpdate();

			try
			{
				_rowChangeLocked = true;
				ListViewItem lvi = Items[index];

				ColorDataSet.ColorRow c =  lvi.Tag as ColorDataSet.ColorRow;
				c.Delete();
				smallImageList.Images.RemoveAt( index );
				largeImageList.Images.RemoveAt( index );
				Items.RemoveAt(index);

				//remake image list
				if( update ) RemakeImages();

				if( Items.Count == 0 ) return;

				if( select)
				{
					if( index == Items.Count ) Items[ index-1].Selected = true;
					else Items[index].Selected = true;
				}

			}
			finally
			{
				_rowChangeLocked = false;
				if( update ) EndUpdate();
			}

		}

		public ColorDataSet.ColorRow ColorRow( int index)
		{
			return Items[index].Tag as ColorDataSet.ColorRow;
		}

		public ListViewItem ListViewItem( ColorDataSet.ColorRow colorRow )
		{
			for( int i= 0; i < Items.Count; i++)
				if( Items[i].Tag == colorRow ) return Items[i];
			
			return null;
		}


		private void Update( ColorDataSet.ColorRow colorRow)
		{

			this.BeginUpdate();
			ListViewItem lvi = ListViewItem( colorRow );
			this.smallImageList.Images[lvi.ImageIndex] = MakeImage( colorRow, true);
			this.largeImageList.Images[lvi.ImageIndex] = MakeImage( colorRow, false);

			Color color  = Color.FromArgb(colorRow.Opacity,colorRow.Red, colorRow.Green, colorRow.Blue);
			HSB hsb = ColorConverter.ColorToHsb(color);
			CMYK cmyk = ColorConverter.RGBtoCMYK ( new RGB(colorRow.Red, colorRow.Green, colorRow.Blue));

			lvi.SubItems[0].Text= colorRow.Name;
			lvi.SubItems[1].Text= colorRow.Red.ToString(null,null); 
			lvi.SubItems[2].Text= colorRow.Green.ToString(null,null); 
			lvi.SubItems[3].Text= colorRow.Blue.ToString(null,null); 
			lvi.SubItems[4].Text= colorRow.Opacity.ToString(null,null);
			lvi.SubItems[5].Text= ColorConverter.ARGBToHexString( color );
			lvi.SubItems[6].Text= hsb.Hue.ToString(null,null);
			lvi.SubItems[7].Text= hsb.Saturation.ToString(null,null);
			lvi.SubItems[8].Text= hsb.Brightness.ToString(null,null);
			lvi.SubItems[9].Text= cmyk.Cyan.ToString(null,null);
			lvi.SubItems[10].Text= cmyk.Magenda.ToString(null,null);
			lvi.SubItems[11].Text= cmyk.Yellow.ToString(null,null);
			lvi.SubItems[12].Text= cmyk.Key.ToString(null,null);
			
			lvi.EnsureVisible();
			this.EndUpdate();


			
		}

		private bool _rowChangeLocked;

		private void ColorRowChanged(object sender, ColorPicker.ColorDataSet.ColorRowChangeEvent e)
		{
			if( _rowChangeLocked) return;
			switch ( e.Action )
			{
				case DataRowAction.Add:AddColor( e.Row); break;
				case DataRowAction.Change:Update ( e.Row ); break;
				default:break;

			}
		}

		private void ColorRowDeleted(object sender, ColorPicker.ColorDataSet.ColorRowChangeEvent e)
		{
			if( _rowChangeLocked) return;
			Remove( e.Row);

		}

		private Bitmap MakeImage(ColorDataSet.ColorRow c, bool small )
		{
			Size s = this.largeImageList.ImageSize;//Large
			if( small ) s = this.smallImageList.ImageSize;

			Rectangle rect = new Rectangle( 0,0,s.Width,s.Height);
			Bitmap bmp = new Bitmap( s.Width,s.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb);

			using( Graphics g = Graphics.FromImage( bmp ))
			{

				g.FillRectangle(Brushes.White, rect);

				if( !small)
				{
					rect.Width--;rect.Height--;
					g.DrawRectangle( SystemPens.ControlDark,  rect);
					rect.Width++;rect.Height++;
					rect.Inflate(-3,-3);
				}

				bool empty = c.Opacity == 0 && c.Red==0 && c.Green == 0 && c.Blue == 0 ;
				if( empty )
				{
					Rectangle b = rect;
					b.Inflate(-3,-2);
						
					Point leftTop		= new Point(b.Left, b.Top);
					Point leftBottom	= new Point(b.Left, b.Bottom);
					Point rightTop		= new Point(b.Right, b.Top);
					Point rightBottom	= new Point(b.Right, b.Bottom);
					Pen pen = Pens.Red;
					g.DrawLine( pen,leftTop, rightBottom);
					g.DrawLine( pen,leftBottom, rightTop);
					return bmp;
				}

				if( c.Opacity < 255)
				{
					RectangleF rt = rect;
					rt.Width /=2f;
					rt.Height/=2f;
					g.FillRectangle( Brushes.Black, rt);
					rt.X += rt.Width;
					rt.Y += rt.Height;
					g.FillRectangle( Brushes.Black, rt);
				}

				using( SolidBrush sb = new SolidBrush( Color.FromArgb(c.Opacity, c.Red, c.Green, c.Blue)))
					g.FillRectangle(sb, rect);

				return bmp;

			}
		}


		#endregion Dataset
		
		public void ShowSystemColors()
		{
			string[] systemColors = ColorConverter.SystemColorNames;
			ColorDataSet cds = new ColorDataSet();
			for( int i = 0; i< systemColors.Length;i++)
			{
				Color c = Color.FromName( systemColors[i]);
				cds.Color.AddColorRow( systemColors[i],c.A, c.R, c.G, c.B );
			}

			this.DataSource = cds;

		}

		public void ShowWebColors()
		{
			string[] webColors = ColorConverter.WebColorNames;
			ColorDataSet cds = new ColorDataSet();
			for( int i = 0; i< webColors.Length;i++)
			{
				Color c = Color.FromName( webColors[i]);
				cds.Color.AddColorRow( webColors[i],c.A, c.R, c.G, c.B );
			}

			this.DataSource = cds;

		}


		public void ShowWebSafeColor()
		{
			
			ColorDataSet cds = new ColorDataSet();
			int[] rgb = new int[]{0,51,102,153,204,255};

			for( int r = 0; r < rgb.Length; r++)
				for( int g = 0; g < rgb.Length; g++)
					for( int b = 0; b < rgb.Length; b++)
					{
						Color c = Color.FromArgb( rgb[r], rgb[g], rgb[b]);
						string name = ColorTranslator.ToHtml(c);// ColorConverter.RGBToHexString( c );//
						cds.Color.AddColorRow( name,c.A,c.R, c.G, c.B );
					}

			this.DataSource = cds;

		}

		public void ShowRealSafeColors()
		{
			ColorDataSet cds = new ColorDataSet();

			Color[] realSafeColors = new Color[]
			{
				Color.FromArgb(0x00,0x00,0x00),
				Color.FromArgb(0xff,0x00,0x00),
				Color.FromArgb(0x00,0x00,0x33),
				Color.FromArgb(0xff,0x00,0x33),
				Color.FromArgb(0x00,0x00,0xff),
				Color.FromArgb(0xff,0x00,0xff),
				Color.FromArgb(0x00,0xff,0x00),
				Color.FromArgb(0x66,0xff,0x00),
				Color.FromArgb(0xff,0xff,0x00),
				Color.FromArgb(0x33,0xff,0x33),
				Color.FromArgb(0x66,0xff,0x33),
				Color.FromArgb(0xff,0xff,0x33),
				Color.FromArgb(0x00,0xff,0x66),
				Color.FromArgb(0x33,0xff,0x66),
				Color.FromArgb(0xcc,0xff,0x66),
				Color.FromArgb(0xff,0xff,0x66),
				Color.FromArgb(0x00,0xff,0xcc),
				Color.FromArgb(0x33,0xff,0xcc),
				Color.FromArgb(0x00,0xff,0xff),
				Color.FromArgb(0x33,0xff,0xff),
				Color.FromArgb(0x66,0xff,0xff),
				Color.FromArgb(0xff,0xff,0xff)
			};


			foreach( Color c in realSafeColors)
			{
				string name = ColorTranslator.ToHtml(c);//ColorConverter.RGBToHexString( c );
				cds.Color.AddColorRow( name,255,c.R, c.G, c.B );
			}

			this.DataSource = cds;
		}

		protected override void OnAfterLabelEdit(LabelEditEventArgs e)
		{

			_rowChangeLocked = true;
			try
			{
				ListViewItem lvi = Items[e.Item];
				ColorDataSet.ColorRow ci = lvi.Tag as ColorDataSet.ColorRow;
				if( e.Label != null && ci.Name != e.Label ) ci.Name = e.Label;
				base.OnAfterLabelEdit (e);
			}
			finally
			{
				_rowChangeLocked = false;
			}
		}


		private bool _editOnReturnKey;

		[DefaultValue( false)]
		public bool EditOnReturnKey
		{
			get{ return _editOnReturnKey;}
			set{ _editOnReturnKey = value;}

		}

		protected override void OnKeyDown(KeyEventArgs e)
		{
			if( _editOnReturnKey && SelectedIndices.Count == 1 && e.KeyCode == Keys.Return )
			{
				ListViewItem lvi = this.SelectedItems[0];
				lvi.BeginEdit();
			}
			base.OnKeyDown (e);
		}

		int oldIndex = -1;
		protected override void OnSelectedIndexChanged(EventArgs e)
		{
			if(  this.SelectedItems.Count == 1 || 
				(this.SelectedItems.Count > 0 && oldIndex != this.SelectedIndices[0]))
			{
				oldIndex = this.SelectedIndices[0];

				ListViewItem lvi = SelectedItems[0];
				if( lvi.Tag != null)
				{
					ColorDataSet.ColorRow ci = lvi.Tag as ColorDataSet.ColorRow;
					ColorRenderingValue.Color = Color.FromArgb(  ci.Red, ci.Green, ci.Blue);
					ColorRenderingValue.Opacity = ci.Opacity;
				}

				this.SelectedItems[0].EnsureVisible();
			}

			base.OnSelectedIndexChanged (e);
		
		}

		protected override void OnColumnClick(ColumnClickEventArgs e)
		{
			base.OnColumnClick (e);
			// Set the ListViewItemSorter property to a new ListViewItemComparer 
			// object. Setting this property immediately sorts the 
			// ListView using the ListViewItemComparer object.
			this.BeginUpdate();
			if( this.Sorting == SortOrder.Descending) this.Sorting = SortOrder.Ascending;
			else if( this.Sorting == SortOrder.Ascending) this.Sorting = SortOrder.Descending;
			else this.Sorting = SortOrder.Ascending;

			this.ListViewItemSorter = new ListViewItemComparer( e.Column , this.Sorting == SortOrder.Ascending);

			this.EndUpdate();
		}


		public void SetSelectedColor( Color color )
		{
		
			this.SelectedItems.Clear();

			foreach( ListViewItem lvi in this.Items)
			{
				ColorDataSet.ColorRow cr = lvi.Tag as ColorDataSet.ColorRow;
				if( cr == null) continue;

				if( color.A== cr.Opacity && color.R== cr.Red && color.G == cr.Green && color.B == cr.Blue)
				{	lvi.Selected = true;break; }
			}

		}

		public void SetColors(Color[] colors)
		{
			SetColors( colors, -1 );
		}

		public void SetColors(Color[] colors, int selectedIndex)
		{

			ColorDataSet cds = new ColorDataSet();

			foreach( Color c in colors)
			{
				string name = c.Name;
				if( ColorConverter.IsEmpty( c )) name =  "Empty";
				else if( !c.IsNamedColor ) 
				{
					name = ColorConverter.GetColorName( c.R,c.G,c.B, c.A );
					if( name == ColorConverter.UNKNOWN_COLOR_TEXT) name = c.Name.ToUpper();
				}

				cds.Color.AddColorRow( name, c.A, c.R, c.G, c.B );
			}

			cds.AcceptChanges();

			this.DataSource = cds;

			if( selectedIndex >=0 && selectedIndex < colors.Length)
			{
				this.SelectedItems.Clear();
				this.Items[selectedIndex].Selected = true;
			}

		}


		public Color[] GetColors( bool sorted )
		{
			if( sorted )
			{
				Color[] colors = new Color[this.Items.Count];
				for( int i = 0; i< this.Items.Count; i++ )
				{
					ListViewItem lvi = this.Items[i];
					ColorDataSet.ColorRow cr = lvi.Tag as ColorDataSet.ColorRow;
					if( cr == null) continue;

					int r = cr.Red;
					int g = cr.Green;
					int b = cr.Blue;
					int a = cr.Opacity;
					
					
					Color c = Color.FromArgb( a, r, g, b);

					if(ColorConverter.IsEmpty( c)) c = Color.Empty;
					else if(ColorConverter.IsTransparent( c)) c = Color.Transparent;
					else if( c.A == 255)
					{
						string name = ColorConverter.GetColorName( c.R, c.G, c.B);
						if(name != ColorConverter.UNKNOWN_COLOR_TEXT ) c = Color.FromName( name );
					}
					
					colors[i] = c;

				}


				return colors;
			}
			else
			{
				ColorDataSet cds = this.DataSource;
						
				if( cds == null || cds.Color.Rows.Count == 0)
					return new Color[]{};

				Color[] colors = new Color[cds.Color.Rows.Count];
				int i = 0;
				foreach( ColorDataSet.ColorRow cr in cds.Color.Rows)
				{
					if( cr.RowState == DataRowState.Deleted || cr.RowState == DataRowState.Detached)
						continue;

					Color c = Color.FromArgb( cr.Opacity, cr.Red, cr.Green, cr.Blue);

					if(ColorConverter.IsEmpty( c)) c = Color.Empty;
					else if(ColorConverter.IsTransparent( c)) c = Color.Transparent;
					else if( c.A == 255)
					{
						string name = ColorConverter.GetColorName( c.R, c.G, c.B);
						if(name != ColorConverter.UNKNOWN_COLOR_TEXT ) c = Color.FromName( name );
					}

					colors[i++] = c;
				}

				return colors;
			}
		}

		#region Comparer
		// Implements the manual sorting of items by columns.
		class ListViewItemComparer : IComparer
		{
			private int		_column;
			private bool	_ascending	= true;

			public const int COLUMN_NAME	= 0;
			public const int COLUMN_R		= 1;
			public const int COLUMN_G		= 2;
			public const int COLUMN_B		= 3;
			public const int COLUMN_A		= 4;
			public const int COLUMN_HEX		= 5;
			public const int COLUMN_H		= 6;
			public const int COLUMN_S		= 7;
			public const int COLUMN_L		= 8;
			public const int COLUMN_C		= 9;
			public const int COLUMN_M		= 10;
			public const int COLUMN_Y		= 11;
			public const int COLUMN_K		= 12;



			public ListViewItemComparer()
			{
			}
			public ListViewItemComparer(int column , bool ascending )
			{
				_ascending	= ascending;
				_column		= column;
			}
			public int Compare(object lviObj1, object lviObj2)
			{
				ListViewItem lvi1 = (ListViewItem)lviObj1;
				ListViewItem lvi2 = (ListViewItem)lviObj2;
				ColorDataSet.ColorRow cr1 = lvi1.Tag as ColorDataSet.ColorRow;
				ColorDataSet.ColorRow cr2 = lvi2.Tag as ColorDataSet.ColorRow;

				int sortAscending = _ascending ? 1:-1;
				int result = 0;

				if( _column == COLUMN_NAME || _column == COLUMN_HEX  )
					result = String.Compare(lvi1.SubItems[_column].Text, lvi2.SubItems[_column].Text);

				if( _column == COLUMN_R )
				{
					if( cr1.Red > cr2.Red ) result = 1;
					if( cr1.Red < cr2.Red ) result = -1;
				}

				if( _column == COLUMN_G )
				{
					if( cr1.Green > cr2.Green ) result = 1;
					if( cr1.Green < cr2.Green ) result = -1;
				}

				if( _column == COLUMN_B )
				{
					if( cr1.Blue > cr2.Blue ) result = 1;
					if( cr1.Blue < cr2.Blue ) result = -1;
				}

				if( _column == COLUMN_A)
				{
					if( cr1.Opacity > cr2.Opacity ) result = 1;
					if( cr1.Opacity < cr2.Opacity ) result = -1;
				}

				if( _column == COLUMN_H || _column == COLUMN_S || _column == COLUMN_L)
				{
					int H1 = Convert.ToInt32( lvi1.SubItems[COLUMN_H].Text , null);
					int H2 = Convert.ToInt32( lvi2.SubItems[COLUMN_H].Text , null);
					int S1 = Convert.ToInt32( lvi1.SubItems[COLUMN_S].Text , null);
					int S2 = Convert.ToInt32( lvi2.SubItems[COLUMN_S].Text , null);
					int L1 = Convert.ToInt32( lvi1.SubItems[COLUMN_L].Text , null);
					int L2 = Convert.ToInt32( lvi2.SubItems[COLUMN_L].Text , null);

					if( _column == COLUMN_H)
					{
						if( H1 > H2 ) result = 1;
						if( H1 < H2 ) result = -1;
					}

					if( _column == COLUMN_S)
					{
						if( S1 > S2 ) result = 1;
						if( S1 < S2 ) result = -1;
					}

					if( _column == COLUMN_L)
					{
						if( L1 > L2 ) result = 1;
						if( L1 < L2 ) result = -1;
					}
				}

				if( _column == COLUMN_C || _column == COLUMN_M || _column == COLUMN_Y || _column == COLUMN_K)
				{

					CMYK cmyk1 = ColorConverter.RGBtoCMYK( new RGB(cr1.Red, cr1.Green, cr1.Blue));
					CMYK cmyk2 = ColorConverter.RGBtoCMYK( new RGB(cr2.Red, cr2.Green, cr2.Blue));

					if( _column == COLUMN_C)
					{
						if( cmyk1.Cyan > cmyk2.Cyan) result = 1;
						if( cmyk1.Cyan < cmyk2.Cyan ) result = -1;

					}
					
					if( _column == COLUMN_M)
					{
						if( cmyk1.Magenda > cmyk2.Magenda) result = 1;
						if( cmyk1.Magenda < cmyk2.Magenda ) result = -1;
					}
					
					if( _column == COLUMN_Y)
					{
						if( cmyk1.Yellow > cmyk2.Yellow ) result = 1;
						if( cmyk1.Yellow < cmyk2.Yellow ) result = -1;
					}

					if( _column == COLUMN_K)
					{
						if( cmyk1.Key > cmyk2.Key ) result = 1;
						if( cmyk1.Key < cmyk2.Key ) result = -1;
					}


				}

				return sortAscending * result;
			}
		}
		#endregion Comparer


	}
}
